/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.facebook.presto.obs;

import com.facebook.airlift.configuration.Config;
import com.facebook.airlift.configuration.ConfigDescription;
import com.facebook.airlift.configuration.ConfigSecuritySensitive;
import com.google.common.base.StandardSystemProperty;
import io.airlift.units.DataSize;
import io.airlift.units.Duration;
import io.airlift.units.MaxDataSize;
import io.airlift.units.MinDataSize;
import io.airlift.units.MinDuration;

import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.io.File;
import java.util.concurrent.TimeUnit;

import static io.airlift.units.DataSize.Unit.MEGABYTE;

public class HiveObsConfig
{
    private String obsAccessKey;
    private String obsSecretKey;
    private String obsEndpoint;
    private String obsSecurityToken;
    private PrestoObsStorageClass obsStorageClass = PrestoObsStorageClass.STANDARD;
    private boolean obsPathStyleAccess = false;
    private boolean obsSslEnabled = true;
    private boolean obsSseEnabled;
    private PrestoObsSseType obsSseType = PrestoObsSseType.KMS;
    private String obsSseKmsKeyId;
    private String obsSseCKeyBase64;
    private int obsMaxClientRetries = 5;
    private int obsMaxErrorRetries = 10;
    private Duration obsMaxBackoffTime = new Duration(10, TimeUnit.MINUTES);
    private Duration obsMaxRetryTime = new Duration(10, TimeUnit.MINUTES);
    private Duration obsConnectTimeout = new Duration(5, TimeUnit.SECONDS);
    private Duration obsSocketTimeout = new Duration(5, TimeUnit.SECONDS);

    /**
     * 最大允许的HTTP并发请求数。默认为500。
     */
    private int obsMaxConnections = 500;

    private File obsStagingDirectory = new File(StandardSystemProperty.JAVA_IO_TMPDIR.value());
    private boolean obsStreamingUploadEnabled = true;
    private DataSize obsStreamingPartSize = new DataSize(16, MEGABYTE);

    /**
     * 桶或对象的访问权限枚举
     */
    private PrestoObsAclType obsAclType = PrestoObsAclType.PRIVATE;

    private boolean skipGlacierObjects;

    public String getObsAccessKey()
    {
        return obsAccessKey;
    }

    @Config("hive.obs.access-key")
    public HiveObsConfig setObsAccessKey(String obsAccessKey)
    {
        this.obsAccessKey = obsAccessKey;
        return this;
    }

    public String getObsSecretKey()
    {
        return obsSecretKey;
    }

    @Config("hive.obs.secret-key")
    @ConfigSecuritySensitive
    public HiveObsConfig setObsSecretKey(String obsSecretKey)
    {
        this.obsSecretKey = obsSecretKey;
        return this;
    }

    public String getObsEndpoint()
    {
        return obsEndpoint;
    }

    @Config("hive.obs.endpoint")
    public HiveObsConfig setObsEndpoint(String obsEndpoint)
    {
        this.obsEndpoint = obsEndpoint;
        return this;
    }

    public String getObsSecurityToken()
    {
        return obsSecurityToken;
    }

    @Config("hive.obs.security-token")
    public HiveObsConfig setObsSecurityToken(String obsSecurityToken)
    {
        this.obsSecurityToken = obsSecurityToken;
        return this;
    }

    @NotNull
    public PrestoObsStorageClass getObsStorageClass()
    {
        return obsStorageClass;
    }

    @Config("hive.obs.storage-class")
    @ConfigDescription("Obs storage class to use when writing the data")
    public HiveObsConfig setObsStorageClass(PrestoObsStorageClass obsStorageClass)
    {
        this.obsStorageClass = obsStorageClass;
        return this;
    }

    public boolean isObsPathStyleAccess()
    {
        return obsPathStyleAccess;
    }

    @Config("hive.obs.path-style-access")
    @ConfigDescription("Use path-style access for all request to obs")
    public HiveObsConfig setObsPathStyleAccess(boolean obsPathStyleAccess)
    {
        this.obsPathStyleAccess = obsPathStyleAccess;
        return this;
    }

    public boolean isObsSslEnabled()
    {
        return obsSslEnabled;
    }

    @Config("hive.obs.ssl.enabled")
    public HiveObsConfig setObsSslEnabled(boolean obsSslEnabled)
    {
        this.obsSslEnabled = obsSslEnabled;
        return this;
    }

    public boolean isObsSseEnabled()
    {
        return obsSseEnabled;
    }

    @Config("hive.obs.sse.enabled")
    @ConfigDescription("Enable obs server side encryption")
    public HiveObsConfig setObsSseEnabled(boolean obsSseEnabled)
    {
        this.obsSseEnabled = obsSseEnabled;
        return this;
    }

    @NotNull
    public PrestoObsSseType getObsSseType()
    {
        return obsSseType;
    }

    @Config("hive.obs.sse.type")
    @ConfigDescription("Key management type for C server-side encryption (C or KMS)")
    public HiveObsConfig setObsSseType(PrestoObsSseType obsSseType)
    {
        this.obsSseType = obsSseType;
        return this;
    }

    public String getObsSseKmsKeyId()
    {
        return obsSseKmsKeyId;
    }

    @Config("hive.obs.sse.kms-key-id")
    @ConfigDescription("KMS Key ID to use for obs server-side encryption with KMS-managed key")
    public HiveObsConfig setObsSseKmsKeyId(String obsSseKmsKeyId)
    {
        this.obsSseKmsKeyId = obsSseKmsKeyId;
        return this;
    }

    public String getObsSseCKeyBase64()
    {
        return obsSseCKeyBase64;
    }

    @Config("hive.obs.sse.c-key-base64")
    public HiveObsConfig setObsSseCKeyBase64(String obsSseCKeyBase64)
    {
        this.obsSseCKeyBase64 = obsSseCKeyBase64;
        return this;
    }

    @Min(0)
    public int getObsMaxClientRetries() { return obsMaxClientRetries;}

    @Config("hive.obs.max-client-retries")
    public HiveObsConfig setObsMaxClientRetries(int obsMaxClientRetries)
    {
        this.obsMaxClientRetries = obsMaxClientRetries;
        return this;
    }

    @Min(1)
    public int getObsMaxErrorRetries()
    {
        return obsMaxErrorRetries;
    }

    @Config("hive.obs.max-error-retries")
    public HiveObsConfig setObsMaxErrorRetries(int obsMaxErrorRetries)
    {
        this.obsMaxErrorRetries = obsMaxErrorRetries;
        return this;
    }

    @MinDuration("1s")
    @NotNull
    public Duration getObsMaxBackoffTime() { return obsMaxBackoffTime; }

    @Config("hive.obs.max-backoff-time")
    public HiveObsConfig setObsMaxBackoffTime(Duration obsMaxBackoffTime)
    {
        this.obsMaxBackoffTime = obsMaxBackoffTime;
        return this;
    }

    @MinDuration("1ms")
    @NotNull
    public Duration getObsMaxRetryTime() { return obsMaxRetryTime; }

    @Config("hive.obs.max-retry-time")
    public HiveObsConfig setObsMaxRetryTime(Duration obsMaxRetryTime)
    {
        this.obsMaxRetryTime = obsMaxRetryTime;
        return this;
    }

    @MinDuration("1ms")
    @NotNull
    public Duration getObsConnectTimeout()
    {
        return obsConnectTimeout;
    }

    @Config("hive.obs.connect-timeout")
    public HiveObsConfig setObsConnectTimeout(Duration obsConnectTimeout)
    {
        this.obsConnectTimeout = obsConnectTimeout;
        return this;
    }

    @MinDuration("1ms")
    @NotNull
    public Duration getObsSocketTimeout()
    {
        return obsSocketTimeout;
    }

    @Config("hive.obs.socket-timeout")
    public HiveObsConfig setObsSocketTimeout(Duration obsSocketTimeout)
    {
        this.obsSocketTimeout = obsSocketTimeout;
        return this;
    }

    @Min(1)
    public int getObsMaxConnections()
    {
        return obsMaxConnections;
    }

    @Config("hive.obs.max-connections")
    public HiveObsConfig setObsMaxConnections(int obsMaxConnections)
    {
        this.obsMaxConnections = obsMaxConnections;
        return this;
    }

    @NotNull
    public File getObsStagingDirectory()
    {
        return obsStagingDirectory;
    }

    @Config("hive.obs.staging-directory")
    @ConfigDescription("Temporary directory for staging files before uploading to OBS")
    public HiveObsConfig setObsStagingDirectory(File obsStagingDirectory)
    {
        this.obsStagingDirectory = obsStagingDirectory;
        return this;
    }

    public boolean isObsStreamingUploadEnabled()
    {
        return obsStreamingUploadEnabled;
    }

    @Config("hive.obs.streaming.enabled")
    public HiveObsConfig setObsStreamingUploadEnabled(boolean obsStreamingUploadEnabled)
    {
        this.obsStreamingUploadEnabled = obsStreamingUploadEnabled;
        return this;
    }

    @NotNull
    @MinDataSize("5MB")
    @MaxDataSize("256MB")
    public DataSize getObsStreamingPartSize()
    {
        return obsStreamingPartSize;
    }

    @Config("hive.obs.streaming.part-size")
    @ConfigDescription("Part size for obs streaming upload")
    public HiveObsConfig setObsStreamingPartSize(DataSize obsStreamingPartSize)
    {
        this.obsStreamingPartSize = obsStreamingPartSize;
        return this;
    }

    @NotNull
    public PrestoObsAclType getObsAclType()
    {
        return obsAclType;
    }

    @Config("hive.obs.upload-acl-type")
    @ConfigDescription("Canned ACL type for Obs uploads")
    public HiveObsConfig setObsAclType(PrestoObsAclType obsAclType)
    {
        this.obsAclType = obsAclType;
        return this;
    }

    public boolean isSkipGlacierObjects()
    {
        return skipGlacierObjects;
    }

    @Config("hive.obs.skip-glacier-objects")
    public HiveObsConfig setSkipGlacierObjects(boolean skipGlacierObjects)
    {
        this.skipGlacierObjects = skipGlacierObjects;
        return this;
    }

}
